﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Markup;

using agree.schema;

using alib;
using alib.Debugging;
using alib.Enumerable;

namespace agree
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DebuggerDisplay("{ToString(),nq}")]
	[TypeConverter(typeof(_conv))]
	public struct ItemCulture : IEquatable<ItemCulture>, IEquatable<CultureInfo>
	{
		public ItemCulture(int lcid)
		{
			this.k = lcid;
		}
		public ItemCulture(String lang)
		{
			this.k = new CultureInfo(lang).LCID;
		}

		int k;
		public int LCID
		{
			get { return k; }
			set { k = value; }
		}

		public String IeftLanguageTag
		{
			get { return this.CultureInfo.IetfLanguageTag; }
			set
			{
				try { k = new CultureInfo(value).LCID; }
				catch { k = 0; }
			}
		}

		public bool IsValid { get { return k != 0; } }

		public CultureInfo CultureInfo
		{
			get { return k != 0 ? new CultureInfo(k) : CultureInfo.InvariantCulture; }
			set { k = value.LCID; }
		}
		public static implicit operator CultureInfo(ItemCulture _this) { return _this.CultureInfo; }

		public bool Equals(ItemCulture other) { return other.k == k; }

		public override bool Equals(object obj)
		{
			return (obj is ItemCulture && ((ItemCulture)obj).k == k) ||
					(obj is CultureInfo && ((CultureInfo)obj).LCID == k);
		}

		public override int GetHashCode() { return k; }

		public bool Equals(CultureInfo other) { return k == other.LCID; }

		public override String ToString() { return k != 0 ? new CultureInfo(k).ToString() : "0"; }

		public sealed class _conv : TypeConverter
		{
			public override bool CanConvertFrom(ITypeDescriptorContext context, System.Type sourceType)
			{
				return typeof(String).IsAssignableFrom(sourceType) || typeof(IString).IsAssignableFrom(sourceType);
			}
			public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
			{
				String s = value as String;
				if (s == null)
					s = ((IString)value).Text;
				return new ItemCulture(s);
			}
		}
	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[ContentProperty("Text")]
	[XmlLangProperty("lang")]
	//[DebuggerTypeProxy(typeof(_iidentity_debug))]
	[DebuggerDisplay("{alib.String._string_ext.DoubleQuote(ToString()),nq}")]
	public class StringItem : identity_seq, IString, IEquatable<IString>, IEquatable<StringItem>, IEquatable<String>,
		ρρItemEnable,
		ρρItemIndex,
		ρρExternalId,
		ρρItemCulture
	{
		public static readonly StringItem Empty;

		static StringItem()
		{
			Empty = new StringItem(SysObj.Instance, String.Empty);
		}

		[DebuggerStepThrough]
		public StringItem(IIdentity prv, String text)
			: base(prv)
		{
			this.ItemEnable = true;
			this.text = text ?? String.Empty;
		}
		[DebuggerStepThrough]
		public StringItem(IIdentity prv)
			: this(prv, default(String))
		{
		}

		[DebuggerStepThrough]
		public StringItem(String text)
			: this(default(IIdentity), text)
		{
		}

		[DebuggerStepThrough]
		public StringItem()
			: this(default(String))
		{
			throw not.valid;
		}

		[DebuggerStepThrough]
		public StringItem(String fmt, params Object[] args)
			: this(fmt == null || args.Length == 0 ? fmt : String.Format(fmt, args))
		{
		}

		///////////////////////////////////////////////////////////////////////
		/// 
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		ItemCulture culture;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public String lang
		{
			get { return this.culture.IeftLanguageTag; }
			set { this.culture = new ItemCulture(value); }
		}

		public ItemCulture ItemCulture
		{
			get { return this.culture; }
			set { this.culture = value; }
		}
		/// 
		///////////////////////////////////////////////////////////////////////


		///////////////////////////////////////////////////////////////////////
		/// 
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		protected String text;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public String Text
		{
			get { return this.text; }
			set { this.text = value; }
		}
		/// 
		///////////////////////////////////////////////////////////////////////

		public Boolean ItemEnable { get; set; }

		public int ItemIndex { get; set; }

		public int ExternalId { get; set; }

		public override bool Equals(Object o) { return Equals(o as IString) || Equals(o as String); }

		public bool Equals(IString o) { return o != null && Equals(o.Text); }

		public bool Equals(String o) { return o != null && this.text == o; }

		public bool Equals(StringItem o) { return o != null && this.text == o.text; }

		public override String ToString() { return text ?? String.Empty; }
		public override int GetHashCode() { return text.GetHashCode(); }
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public static class language_obj_utils
	{
		public static String recover_string_content(Object obj)
		{
			if (obj == null)
				return String.Empty;

			if (obj is IString)
				obj = ((IString)obj).Text;
			else if (obj is StringBuilder)
				obj = ((StringBuilder)obj).ToString();
			else if (obj is TextReader)
				obj = ((TextReader)obj).ReadToEnd();

			if (obj is String)
				return (String)obj;

			String iv;
			if (obj is IIdentity && (iv = (String)PP.Text.GetValue(obj)) != null)
				return iv;

			var t1 = obj as Task;
			if (t1 != null)
			{
				if (t1.IsFaulted)
					throw t1.Exception;

				var pi = t1.GetType().GetProperty("Result");
				if (pi != null)
					return recover_string_content(pi.GetValue(t1));

				if (!t1.IsCompleted)
					t1.Wait();
				return recover_string_content(obj);
			}

			var t2 = obj as IObservable<String>;
			if (t2 != null)
				return recover_string_content(System.Reactive.Threading.Tasks.TaskObservableExtensions.ToTask(t2));

			var t3 = obj as IEnumerable;
			if (t3 != null)
				return recover_string_content(t3.StringJoin(" "));

			return obj.ToString();
		}
	};
}